/**
 * AI 对话
 * */
import {
  getChatData,
  deleteChatData,
  getChatDataDetail,
  getChatDataDetailSuggest,
} from "@/api/aiChat";
import userStore from "./user.js";
import config from "@/utils/config";
const state = {
  // 是否全屏
  fullscreen: localStorage.getItem("Fullscreen-Key") === "false" ? false : true,
  // 窗口大小 max | min
  widthSizeType: "max",
  // 整体弹窗 show
  showAideIA: false,
  // 提交问题加载
  loading: false,
  // 内容加载
  homeLoading: false,
  // 左侧折叠
  handleShow: true,
  // 选中对话类型 默认：''
  moduleType: "CHAT",
  // 对话id
  contextId: "",
  // 最近对话纪录
  chatData: [],
  chatDataItem: [],
  // 对话类型
  functionData: [
    {
      name: "文档总结",
      icon: "el-icon-document",
      type: "DOC",
      content: "速读各类文章，迅速了解摘 要和洞察。",
    },
    {
      name: "企业知识库",
      icon: "el-icon-mobile",
      type: "KNOWLEDGE",
      content: "依赖企业知识库，智能回答。 例如‘如何保证脚手架安全搭建’",
    },
    {
      name: "业务助手",
      icon: "el-icon-user",
      type: "BUSINESS",
      content: "快捷对接业务，例如‘2024 年12月的高风险月报表导出’",
    },
    {
      name: "图片识别",
      icon: "el-icon-picture-outline",
      type: "IMG",
      content: "分析图片，助您决策。例如 ‘是否佩戴安全帽’",
    },
  ],
  // 下一步建议
  chatSuggestList: [],
  // 下一步建议 加载
  suggestLoading: false,
};

const mutations = {
  // 全屏切换
  SET_FULLSCREEN: (state, status) => {
    state.fullscreen = status;
    localStorage.setItem("Fullscreen-Key", status);
  },
  // 左侧折叠 show
  SRT_HANDLE_SHOW: (state, status) => {
    state.handleShow = status;
  },
  // max/min 窗口大小
  SET_WIDTH_SIZE_TYPE: (state, widthSizeType) => {
    state.widthSizeType = widthSizeType;
  },
  // 提问类型
  SET_MODULE_TYPE: (state, moduleType) => {
    state.moduleType = moduleType;
  },
  // 当前对话id
  SET_CONTEXT_ID: (state, contextId) => {
    state.contextId = contextId;
  },
  // 对话历史纪录
  SET_CHAT_DATA: (state, data) => {
    state.chatData = data;
  },
  // 对话详情
  SET_CHAT_DATA_ITEM: (state, data) => {
    state.chatDataItem = data;
  },
  // 提交问题加载
  SET_LOADING: (state, data) => {
    state.loading = data;
  },
  // 内容加载
  SET_HOME_LOADING: (state, data) => {
    state.homeLoading = data;
  },
  // 整体弹窗 show
  CHANGE_AIDEIA: (state, aideIA) => {
    state.showAideIA = aideIA;
  },
  // 下一步建议
  SET_CHATSUGGEST_LIST: (state, data) => {
    state.chatSuggestList = data;
  },
  // 下一步建议loading
  SET_SUGGEXT_LOADING: (state, data) => {
    state.suggestLoading = data;
  },
};

const actions = {
  // AI 弹窗打开
  changeAideIA({ commit }, aideIA) {
    commit("CHANGE_AIDEIA", aideIA);
  },
  // show left 折叠
  setStatus({ commit }, status) {
    commit("SRT_HANDLE_SHOW", status);
  },
  // left 类型 对话类型和其他类型
  setModuleType({ commit }, moduleType) {
    commit("SET_MODULE_TYPE", moduleType);
  },
  // 点击 left 事件 获取聊天详情
  setContextId({ commit, dispatch }, contextId) {
    if (contextId) {
      commit("SET_HOME_LOADING", true);
      getChatDataDetail(contextId).then(({ result }) => {
        commit("SET_HOME_LOADING", false);
        let data = [];
        result.forEach((item) => {
          data.push({
            ...item,
            whomType: "person",
          });
          data.push({
            ...item,
            whomType: "ai",
          });
        });
        commit("SET_CHAT_DATA_ITEM", data);
      });
    } else {
      commit("SET_CHAT_DATA_ITEM", []);
    }
    commit("SET_CONTEXT_ID", contextId);
    // 清空下一步建议&加载loading
    commit("SET_LOADING", false);
    commit("SET_CHATSUGGEST_LIST", []);
  },
  // 获取下一步建议
  getChatSuggest({ state, commit }, query) {
    commit("SET_SUGGEXT_LOADING", true);
    let params = {
      contextId: state.contextId,
      suggestMsgSize: 4,
      isUseHistoryMsg: true,
      useHistoryMsgSize: 4,
    };
    let chatDataItemEnd = state.chatDataItem.length
      ? state.chatDataItem[state.chatDataItem.length - 1]
      : null;
    if (state.moduleType !== "BUSINESS" && (query || chatDataItemEnd)) {
      params = {
        query: query || chatDataItemEnd.query,
      };
      getChatDataDetailSuggest(params).then(({ result }) => {
        commit("SET_CHATSUGGEST_LIST", result);
        commit("SET_SUGGEXT_LOADING", false);
      });
    } else {
      commit("SET_CHATSUGGEST_LIST", []);
      commit("SET_SUGGEXT_LOADING", false);
    }
  },
  // 终止调用
  stopChat({ commit, dispatch }) {
    if (this.adddialState) {
      dispatch("getChatData");
    }
    this.controller.abort(); //保险起见执行一下中断接收
    commit("SET_LOADING", false);
  },
  // fetch 提交对话
  setChatData({ state, commit, dispatch }, data) {
    // loading sta
    commit("SET_LOADING", true);
    this.adddialState = false; // 判断是不是新增
    // 创建 聊天框
    if (!state.contextId) {
      let uid = generateId();
      data.contextId = uid;
      commit("SET_CONTEXT_ID", uid);
      this.adddialState = true;
    } else {
      data.contextId = state.contextId;
    }

    let textNew = {
      query: data.value,
      fileId: data.fileId,
      filePath: data.filePath,
      fileName: data.fileName, // 文件的名称
      fileLink: data.fileLink,
      fileUploadType: data.fileUploadType, // 分辨链接和文件的type
      whomType: "person",
      msgId: generateId(),
      timestamp: new Date().getTime(),
    };
    let textAi = {
      response: "",
      whomType: "ai",
      msgId: generateId(),
      timestamp: new Date().getTime(),
    };
    dispatch("addChatData", {
      title: data.value,
      // 创建 人 细项
      textNew: textNew,
      // ai 初始化
      textAi: textAi,
    });
    // 请求参数
    let params = {
      contextId: data.contextId,
      query: data.value,
      fileId: data.fileId,
      fileLink: data.fileLink,
      fileUploadType: data.fileUploadType,
      type: state.moduleType,
      userId: userStore.state.userInfo.id,
    };
    //注意 最好使用 async await 语法糖 包括后续在拿到请求结果后的异步逻辑也最好做同步处理！
    return new Promise(async (resolve, reject) => {
      let characterString = "";
      // 创建AbortController实例，以便中止请求(比如用于停止生成)
      this.controller = new AbortController();

      this.ok = true; //初始化默认 this.ok为false

      const resp = await fetch(config.jBaseURL + "ai/chat", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(params),
        signal: this.controller.signal, //与其相关联的signal属性
      });
      // 众所周知 fetch .then 写法有两个.then ,在开发使用时我们一般第一个抛出的就是 resp
      //第二个抛出的是 在resp.ok 为true 时的响应body

      if (resp.ok) {
        const reader = resp.body.getReader(); //读取返回结果的流数据方法，内置 .read()方法
        const decoder = new TextDecoder(); //解码器
        //循环拿到所有数据 done读取完毕
        while (this.ok) {
          //解构读取返回数据，在流式接口中，done 为请求结束，value 是未解码前的二进制数据
          const { done, value } = await reader.read();
          if (done) {
            // 已传输完毕
            console.log("完成");
            commit("SET_LOADING", false);
            if (this.adddialState) {
              dispatch("getChatData");
            }
            resolve();
            this.controller.abort(); //保险起见执行一下中断接收
            //这里执行你 数据响应完全的逻辑
            break;
          }
          const str = decoder.decode(value); //二进制解码
          if (!str.trim()) {
            continue;
          }

          let regex = "";
          // console.log("二进制解码", str);
          if (str.includes("data:")) {
            regex = /data:({.*?"knowledgeReferencesEnd":null)/g;
          } else {
            regex = /({.*?"knowledgeReferencesEnd":null)/g;
          }

          const objects = [];
          let match;
          while ((match = regex.exec(str))) {
            // 使用 JSON.parse 将匹配到的字符串转换为对象
            const obj = JSON.parse(match[1] + "}");

            objects.push(obj);
          }

          let num = objects.map((e) => e.response).join("");
          let responseMsgType = objects[0] && objects[0].responseMsgType;
          characterString += num || "";
          let knowledgeReferences =
            objects[objects.length - 1] &&
            objects[objects.length - 1].knowledgeReferences;
          dispatch("addItem", {
            text: characterString,
            responseMsgType: responseMsgType || "MARKDOWN",
            msgId: textAi.msgId,
            knowledgeReferences: knowledgeReferences,
          });
        }
      } else {
        reject(resp.statusText);
        commit("SET_LOADING", false);
      }
    });
  },
  // 对话 细项
  addItem({ state, commit }, data) {
    let chatDataItem = JSON.parse(JSON.stringify(state.chatDataItem));
    chatDataItem.forEach((e) => {
      if (e.msgId === data.msgId) {
        e.responseMsgType = data.responseMsgType;
        e.response = data.text;
        e.knowledgeReferences = data.knowledgeReferences;
      }
    });
    commit("SET_CHAT_DATA_ITEM", chatDataItem);
  },
  // 初始化 历史纪录＆对话
  addChatData({ state, commit, dispatch }, obj) {
    let chatDataItem = JSON.parse(JSON.stringify(state.chatDataItem));
    chatDataItem.push(obj.textNew, obj.textAi);
    commit("SET_CHAT_DATA_ITEM", chatDataItem);
    // 提前回去下一步建议
    dispatch("getChatSuggest", obj.textNew.query);
  },
  getChatData({ state, commit }) {
    // commit("SET_CHAT_DATA", [{contextName: '11212',contextId: 1}]);
    return new Promise(async (resolve, reject) => {
      getChatData({
        userId: userStore.state.userInfo.id,
        pageNum: 1,
        pageSize: 999,
      })
        .then(({ result }) => {
          commit("SET_CHAT_DATA", result.records);
          resolve();
        })
        .catch(() => {
          reject();
        });
    });
  },
  deleteChatData({ state, commit }, data) {
    return new Promise(async (resolve, reject) => {
      deleteChatData(data)
        .then(() => {
          resolve();
        })
        .catch(() => {
          reject();
        });
    });
  },
};

// 前端生成id方法
function generateId() {
  const s = [];
  const hexDigits = "0123456789abcdef";
  for (let i = 0; i < 36; i++) {
    s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
  }
  // bits 12-15 of the time_hi_and_version field to 0010
  s[14] = "4";
  // bits 6-7 of the clock_seq_hi_and_reserved to 01
  s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
  s[8] = s[13] = s[18] = s[23] = "-";
  const uuid = s.join("");
  let date = +new Date();
  return uuid + date;
}
export default {
  namespaced: true,
  state,
  mutations,
  actions,
};
